home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
126-150
/
scopedisk146
/
liner
/
source
/
liner.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-19
|
40KB
|
1,256 lines
/*
'Liner Version 2.00. Written by Dave Schreiber
©1988, 1989, 1990 by Dave Schreiber. All Rights Reserved.
2.00 completed Saturday, June 23, 1990
1.32 completed Monday, October 30, 1989
1.31 completed Friday, October 6, 1989
1.30 completed Saturday, February 25, 1989
1.20 completed Friday, November 11, 1988
1.10 completed Friday, October 14, 1988
1.00 completed Friday, September 9, 1988
Length of source code: 5714 lines
Compiled with Lattice C V5.02
To compile: 1> lc -cw -j30 -L+YAFR:YAFR.o 'Liner
You must assign YAFR: to the directory where YAFR.o is stored.
You must also assign LINER: to the directory where the 'Liner source
is located.
*********************************
'Liner is an outliner, with up to six levels of depth, and up to
52 items per level (each isolated section). It has both clipboard and
non-clipboard support of CUT, COPY, and, for single lines of text, PASTE.
It can output files in its own format, or in ASCII (to disk or printer).
It can read files in its own format only. It uses dynamic memory
allocation to allow an infinite number of items (memory providing).
It supports ARexx, Workbench icons, overscanned and interlaced screens
*********************************
Amiga features of note that are used:
console device, disk i/o, printer i/o, clipboard i/o
*********************************
Intuition objects (screen, windows, gadgets, menus, etc.) generated by
PowerWindows Version 2.0
*********************************
*********************************
V1.1 corrects some bugs, doubles the number of characters available
for filenames, and improves PrintItemList() so that it doesn't always
print the entire item list
------------
1.2 allows the toggling between 640x200 & 640x400 screens and the
choice of the order that levels appear in, has a completely reworked
About... window, lets the user change the level of all the items
in a highlighted block, and now displays the current filename
in the title bar.
------------
1.3 adds support for user-selected keymaps, and now prints an asterisk
in the title bar if an outline has been edited but not saved. It also
includes my very own file requester, YAFR (Yet Another File Requester)
based in principal upon Charlie Heath's, but with a lot more buttons.
------------
1.31 changes the default device where files are located from DF0: to
the current directory
------------
1.32 fixed a bug that kept the screen from updating properly after a
paste. Also uses YAFR V1.1
------------
2.00 added a number of things:
-Two way ARexx support
-Search/replace
-Greater Clipboard support (a block of lines that are CUT or COPYed are
now sent to the Clipboard
-Truer WYSIWYG: double spacing is now shown on screen
-Support for more than one line per number
-Icon support: icons now can be created when a document is saved. When
the icon is double clicked on, 'Liner will be run and the document
loaded
-Support for overscanned screens, allowing more rows of text on screen
at once
-Adjustable screen colors
-An option to save various settings in a preferences file
-A new, more compact file format that supports the new 'Liner's
improvements
-The limit of highlighting only one screenful of lines at a time has
been removed. There is now no limit
-Support for up to 52 lines per level, up from 26 in 1.32
-Uses YAFR V1.20. See the file YAFR.c for more details.
In addition, a bug that would cause 'Liner to crash if the user
attempted to load a file that wasn't a 'Liner outline has been removed
*********************************
*/
#include "globals.h"
/*Outline characters*/
char *OutLineChars[6][99]=
{
{
{"I."},{"II."},{"III."},{"IV."},{"V."},{"VI."},{"VII."},{"VIII."},
{"IX."},{"X."},{"XI."},{"XII."},{"XIII."},{"XIV."},{"XV."},{"XVI."},
{"XVII."},{"XVIII."},{"XIX."},{"XX."},{"XXI."},{"XXII."},{"XXIII."},
{"XXIV."},{"XXV."},{"XXVI."},{"XXVII."},{"XXVIII."},{"XXIX."},{"XXX."},
{"XXXI."},{"XXXII."},{"XXXIII."},{"XXXIV."},{"XXXV."},{"XXXVI."},
{"XXXVII."},{"XXXVIII."},{"IXL."},{"XL."},{"XLI."},{"XLII."},{"XLIII."},
{"XLIV."},{"XLV."},{"XLVI."},{"XLVII."},{"XLVIII."},{"IL."},{"L."},
{"LI."},{"LII."}
},
{
{"A."},{"B."},{"C."},{"D."},{"E."},{"F."},{"G."},{"H."},{"I."},
{"J."},{"K."},{"L."},{"M."},{"N."},{"O."},{"P."},{"Q."},{"R."},
{"S."},{"T."},{"U."},{"V."},{"W."},{"X."},{"Y."},{"Z."},{"AA."},
{"AB."},{"AC."},{"AD."},{"AE."},{"AF."},{"AG."},{"AH."},{"AI."},
{"AJ."},{"AK."},{"AL."},{"AM."},{"AN."},{"AO."},{"AP."},{"AQ."},
{"AR."},{"AS."},{"AT."},{"AU."},{"AV."},{"AW."},{"AX."},{"AY."},
{"AZ."}
},
{
{"1."},{"2."},{"3."},{"4."},{"5."},{"6."},{"7."},{"8."},{"9."},
{"10."},{"11."},{"12."},{"13."},{"14."},{"15."},{"16."},{"17."},
{"18."},{"19."},{"20."},{"21."},{"22."},{"23."},{"24."},{"25."},
{"26."},{"27."},{"28."},{"29."},{"30."},{"31."},{"32."},{"33."},
{"34."},{"35."},{"36."},{"37."},{"38."},{"39."},{"40."},{"41."},
{"42."},{"43."},{"44."},{"45."},{"46."},{"47."},{"48."},{"49."},
{"50."},{"51."},{"52."}
},
{
{"a."},{"b."},{"c."},{"d."},{"e."},{"f."},{"g."},{"h."},{"i."},
{"j."},{"k."},{"l."},{"m."},{"n."},{"o."},{"p."},{"q."},{"r."},
{"s."},{"t."},{"u."},{"v."},{"w."},{"x."},{"y."},{"z."},{"aa."},
{"ab."},{"ac."},{"ad."},{"ae."},{"af."},{"ag."},{"ah."},{"ai."},
{"aj."},{"ak."},{"al."},{"am."},{"an."},{"ao."},{"ap."},{"aq."},
{"ar."},{"as."},{"at."},{"au."},{"av."},{"aw."},{"ax."},{"ay."},
{"az."}
},
{
{"1)"},{"2)"},{"3)"},{"4)"},{"5)"},{"6)"},{"7)"},{"8)"},{"9)"},
{"10)"},{"11)"},{"12)"},{"13)"},{"14)"},{"15)"},{"16)"},{"17)"},
{"18)"},{"19)"},{"20)"},{"21)"},{"22)"},{"23)"},{"24)"},{"25)"},
{"26)"},{"27)"},{"28)"},{"29)"},{"30)"},{"31)"},{"32)"},{"33)"},
{"34)"},{"35)"},{"36)"},{"37)"},{"38)"},{"39)"},{"40)"},{"41)"},
{"42)"},{"43)"},{"44)"},{"45)"},{"46)"},{"47)"},{"48)"},{"49)"},
{"50)"},{"51)"},{"52)"}
},
{
{"a)"},{"b)"},{"c)"},{"d)"},{"e)"},{"f)"},{"g)"},{"h)"},{"i)"},
{"j)"},{"k)"},{"l)"},{"m)"},{"n)"},{"o)"},{"p)"},{"q)"},{"r)"},
{"s)"},{"t)"},{"u)"},{"v)"},{"w)"},{"x)"},{"y)"},{"z)"},{"aa)"},
{"ab)"},{"ac)"},{"ad)"},{"ae)"},{"af)"},{"ag)"},{"ah)"},{"ai)"},
{"aj)"},{"ak)"},{"al)"},{"am)"},{"an)"},{"ao)"},{"ap)"},{"aq)"},
{"ar)"},{"as)"},{"at)"},{"au)"},{"av)"},{"aw)"},{"ax)"},{"ay)"},
{"az)"}
},
};
/*The position of each special character in the array below*/
extern int SCPos[]=
{0,1,4,5,9,13,14,16,17,18,19,20,21,23,25,27,29};
/*Special characters (TAB, RETURN, etc.)*/
extern char SpecChars[]=
{
32,
8,CSI,'P',
0,
0x0D,0x0A,CSI,'L',
0x0D,0x0A,CSI,'L',
0,
CSI,'P',
0,
0,
0,
0,
0,
CSI,'A',
CSI,'B',
CSI,'C',
CSI,'D',
NULL
};
char Inv[]=
{CSI,'7',0x6d,NULL};
char Norm[]=
{CSI,'0',0x6d,NULL};
_main() /*The main function*/
{
ULONG Class;
USHORT Code,Qualifier;
APTR IAddress;
SHORT MouseX,MouseY;
int Seconds,Micros;
struct IntuiMessage *Message;
char Buffer[200];
Buffer[0]=NULL; /*Initialize various variables...*/
FileName[0]=SFileName[0]=SExt[0]=NULL;
strcpy(PDirName,"");
PDName[0]=PFileName[0]=PExt[0]=NULL;
Modified=FALSE; /*No modifications, yet*/
StartingLevel=0;
/*Open all the libraries*/
IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",1);
if(IntuitionBase==NULL) /*Intuition*/
exit(10);
GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",1);
if(GfxBase==NULL) /*Graphics*/
exit(20);
DosBase=OpenLibrary("dos.library",1);
if(DosBase==NULL) /*Dos*/
Leave(30,"Can't open dos.library!");
IconBase=OpenLibrary("icon.library",1);
if(IconBase==NULL) /*Icon*/
Leave(40,"Can't open icon.library!");
OpenARexx(); /*Open the ARexx port*/
ThisProc=(struct Process *)FindTask(NULL);/*Get 'Liner's process structure*/
GetLinerPrefs("liner:liner.prefs"); /*Load the preferences*/
InterpretPrefs(); /*Install the preferences*/
SetupClipboard(); /*Open the clipboard*/
/*Setup various system variable*/
DispRows=1;
PtrX=PtrY=LastX=LastY=1;
ButtonState=UP;
InvsMode=ClipMode=NOINV;
FirstItem=LastItem=FirstScrnItem=CurrentItem=(struct LineItem *)
InsertItem(NULL,NULL);
if(FirstItem==NULL)
{
CloseGraphics();
CloseLibrary(IconBase);
CloseLibrary(GfxBase);
Leave(50,"Memory too fragmented to run 'Liner! Exiting.");
}
FirstItem->Level=1;
FirstItem->ItemNumber=0;
PrintItemList(FirstItem,1);
PlotCursor(MinX(CurrentItem),1);
if(WBenchMsg != 0) /*If called from the Workbench...*/
if(WBenchMsg->sm_NumArgs > 1) /*Outline clicked on instead of 'Liner*/
{
CurrentDir(WBenchMsg->sm_ArgList[1].wa_Lock);
/*Make outline's directory the current directory*/
if(strcmp(WBenchMsg->sm_ArgList[1].wa_Name,"liner.prefs") != 0)
{ /*Make sure user didn't click on liner.prefs icon*/
strcpy(FileName,WBenchMsg->sm_ArgList[1].wa_Name);
strcpy(SFileName,FileName);
/*Store the outline's filename*/
ReadItemList(WBenchMsg->sm_ArgList[1].wa_Name);
/*Load the outline*/
TitleErrorCancel();
}
}
for(;;) /*The main loop!*/
{
/*Wait for something to happen*/
Wait((1<<Window->UserPort->mp_SigBit) | ARexxSigBit);
CheckRexxPort(); /*Check the ARexx port for any messages*/
while((Message=(struct IntuiMessage *) /*Get the message if IDCMP*/
GetMsg(Window->UserPort))!=NULL)
{ /*Get the message's information*/
Class=Message->Class;
Code=Message->Code;
Qualifier=Message->Qualifier;
MouseX=Message->MouseX;
MouseY=Message->MouseY;
Seconds=Message->Seconds;
Micros=Message->Micros;
IAddress=(APTR)Message->IAddress;
ReplyMsg(Message); /*Reply to the message*/
/*Decode the message*/
if(HandleIDCMP(Class,Code,Qualifier,MouseX,MouseY,IAddress,
Buffer,Seconds,Micros))
{ /*If the message was a keypress*/
InsertChar(CurrentItem->Text,Buffer[2], /*Print the letter*/
PosInText(CurrentItem->Level)); /*onto the screen*/
CurX++;
WriteConsole(Buffer,-1);
}
}
}
}
/*Decode an IDCMP message*/
HandleIDCMP(Class,Code,Qualifier,MouseX,MouseY,IAddress,Buffer,Secs,Micros)
ULONG Class;
USHORT Code,Qualifier;
APTR IAddress;
SHORT MouseX,MouseY;
int Secs,Micros;
char *Buffer;
{
struct MenuItem *item;
struct InputEvent KeyEvent;
Buffer[0]=CSI;
Buffer[1]=0x40;
Buffer[2]=NULL;
switch(Class)
{
case MENUPICK: /*There was a menu selection*/
if(ErrorInTitle)
TitleErrorCancel();
while(Code != MENUNULL)
{
item=(struct MenuItem *)GetFirstItemAddress(Code);
HandleEvent(item);
Code=item->NextSelect;
}
case MOUSEBUTTONS: /*The left mouse button was pushed*/
if(Code==SELECTDOWN)
HandleButton(Secs,Micros);
break;
case MOUSEMOVE: /*The mouse was moved*/
MovedMouse(MouseX,MouseY);
break;
/*A key was pressed*/
case RAWKEY: /*By using IDCMP RAWKEY as input, and the*/
if(Code & 0x80) /*console for output, we can both get input*/
return(FALSE); /*and IDCMP messsages without having to try*/
if(ErrorInTitle) /*and decode ASCII console messages*/
TitleErrorCancel(); /*(IDCMP structures are MUCH easier)*/
if(((Code < 0x41) || (0x5a <= Code && Code <= 0x5e) ||
(Code==0x4a)) && !(Qualifier & 8))
{ /*^^^==All the RAWKEY codes for alphanumeric characters*/
CheckModified();
KeyEvent.ie_NextEvent=NULL; /*Create a fake input event*/
KeyEvent.ie_Class=IECLASS_RAWKEY; /*for RawKeyConvert() to */
KeyEvent.ie_SubClass=NULL; /*munch on. Using RawKeyConvert()*/
KeyEvent.ie_Code=Code; /*insures that the current keymap*/
KeyEvent.ie_Qualifier=Qualifier; /*is used*/
RawKeyConvert(&KeyEvent,&Buffer[2],200,&keymap),ConsoleDevice;
Buffer[3]=NULL; /* ^^^ == RAWKEY to ASCII*/
if(InvsMode < NOINV) /*If a block of lines was highlighted*/
{ /*when a key was pressed, cancel the*/
EndBlockInvs(); /*highlight*/
return(FALSE);
}
/*If a key was pressed when TEXT was*/
if(InvsMode) /*highlighted, delete the text & replace*/
DelTextBlock(); /*it with the letter pressed*/
/*If the current line isn't full*/
if(strlen(CurrentItem->Text)<MaxLen(CurrentItem->Level))
return(TRUE); /*OK to print the character*/
else
return(FALSE); /*Otherwise not*/
}
else
switch(Code) /*Handle all the "special" characters*/
{
case 0x4d: /*Move cursor down one*/
CancelLineInvs();
if(Qualifier & 3) /*Handle SHIFT-DOWN*/
WholeScreenDown();
else if(Qualifier & 8) /*Handle CTRL-DOWN*/
JumpToBottom();
else
CursorDown();
break;
case 0x4c: /*Move cursor up one*/
CancelLineInvs();
if(Qualifier & 3) /*Check for shift*/
WholeScreenUp();
else if(Qualifier & 8) /*Check for control*/
JumpToTop();
else
CursorUp();
break;
case 0x4e: /*Move cursor one to the right*/
CursorRight(Qualifier);
break;
case 0x4f: /*Move cursor one to the left*/
CursorLeft(Qualifier);
break;
case 0x41: /*Backspace over a character*/
HandleBS();
break;
case 0x46: /*Delete a character*/
CheckModified();
if(DelInvs())
break;
if(CurX<MaxX(CurrentItem))
{
strcpy(Buffer,&SpecChars[SCPos[6]]);
Buffer[SCPos[7]-SCPos[6]]=NULL;
DeleteChar(CurrentItem->Text,
PosInText(CurrentItem->Level));
WriteConsole(Buffer,-1);
}
break;
case 0x42: /*TAB (in or out)*/
HandleTAB(Qualifier);
break;
case 0x43: /*Return & Enter */
case 0x44: /*Insert a line*/
HandleReturn(Qualifier);
break;
}
return(FALSE);
}
return(FALSE);
}
/*Close everything*/
void CloseStuff()
{
FreeListMem(FirstItem,LastItem); /*Free the outline's memory*/
if(ClipMode < NOINV)
FreeListMem(ClipStart,ClipEnd); /*Delete any clipped lines*/
CloseARexx(); /*Close the ARexx port*/
ShutDownClipboard();
CloseGraphics(); /*Close the screen, etc...*/
CloseLibrary(IconBase); /*Close the libraries*/
CloseLibrary(DosBase);
CloseLibrary(GfxBase);
CloseLibrary(IntuitionBase);
exit(0);
}
void HandleBS() /*Handle the pressing of the backspace key*/
{
char Buffer[20];
CheckModified();
if(DelInvs()) /*If something is highlighted*/
return; /*delete it*/
/*Delete the character, if not at the beginning of the line...*/
if(CurX>MinX(CurrentItem))
{
strcpy(Buffer,&SpecChars[SCPos[1]]);
Buffer[SCPos[2]-SCPos[1]]=NULL;
DeleteChar(CurrentItem->Text,
PosInText(CurrentItem->Level)-1);
WriteConsole(Buffer,-1);
CurX--;
}
else /*otherwise, delete the line*/
if(CurrentItem->PrevItem != NULL &&
strlen(CurrentItem->Text)==0 &&
!(CurrentItem->NextItem && !CurrentItem->cont &&
CurrentItem->NextItem->cont))
{
DelBlock(CurrentItem,CurrentItem,CurY,CurY);
if(CurrentItem != LastItem)
CursorUp();
PlotCursor(MaxX(CurrentItem),CurY);
}
}
HandleReturn(Qualifier) /*The return key was pressed, so add a line...*/
USHORT Qualifier;
{
BYTE TempX,TempY;
char Buffer[20];
struct LineItem *WorkingItem;
CheckModified();
if(CancelInvs())
return(FALSE);
if(CurX == MinX(CurrentItem) && strlen(CurrentItem->Text) > 0)
if(!CursorUp())
{
InsertLineAtTop();
return(FALSE);
}
/*If the next item is a continuation and SHIFT wasn't pressed*/
if((CurrentItem->NextItem != NULL) && !(Qualifier & 3) &&
(CurrentItem->NextItem->cont))
return(FALSE); /*Don't do anything*/
WorkingItem=(struct LineItem *) /*Create the line*/
InsertItem(CurrentItem->NextItem,CurrentItem);
if(WorkingItem==NULL)
{
Leave(0,"Memory too fragmented to add line!"); /*Ran out of memory*/
return(FALSE);
}
if((DispRows==SCRNHEIGHT) && (CurY != SCRNHEIGHT))
{ /*If a full screen & cursor isn't at the bottom*/
TempX=CurX; /*Delete the last line*/
TempY=CurY;
PlotCursor(1,SCRNHEIGHT);
Buffer[0]=0x9b;
Buffer[1]=0x4a;
WriteConsole(Buffer,2);
PlotCursor(TempX,TempY);
}
strcpy(Buffer,&SpecChars[SCPos[4]]); /*Make space for the line*/
WriteConsole(Buffer,4); /*on the screen*/
if(prefs.DS) /*If double spaced*/
{
WriteConsole(Buffer,4); /*Add an extra line*/
if((CurrentItem==ScrnBtm) && (Odd))
WriteConsole(Buffer,4);
}
WorkingItem->Level=CurrentItem->Level;
if(Qualifier & 3) /*If a SHIFT-RETURN*/
{
WorkingItem->cont=TRUE; /*The line is a continuation of the previous*/
WorkingItem->ItemNumber=CurrentItem->ItemNumber; /*line*/
}
else
{ /*Otherwise, it's an independent line*/
WorkingItem->cont=FALSE;
if(CurrentItem->ItemNumber==
MaxNumOnLevel[CurrentItem->Level]-1)
WorkingItem->ItemNumber=0;
else
WorkingItem->ItemNumber=CurrentItem->ItemNumber+1;
}
if(CurY==SCRNHEIGHT) /*If at the bottom of the screen*/
{
if(prefs.DS) /*If double spaced, open up more space*/
WriteConsole(Buffer,4);
ScrnBtm=(struct LineItem *)WorkingItem;
FirstScrnItem=(struct LineItem *)
FirstScrnItem->NextItem;
}
else
{
CurY++;
if(DispRows==SCRNHEIGHT)
ScrnBtm=(struct LineItem *)ScrnBtm->PrevItem;
else
++DispRows;
}
if(WorkingItem->NextItem==NULL) /*If it's at the end of the outline*/
ScrnBtm=LastItem=(struct LineItem *) /*update appropriate pointers*/
WorkingItem;
AddItem(WorkingItem);
TempY=CurY;
RedrawOutlineChars(WorkingItem,WorkingItem->Level,0);
CurrentItem=(struct LineItem *)WorkingItem; /*Make the new line current*/
PlotCursor(MinX(CurrentItem),TempY); /*and put the cursor on it*/
}
void Leave(err,why) /*If an error occured, tell user, close window & screen*/
int err; /*& exit*/
char *why;
{
char whyindeed[256];
SHORT x;
/*Construct the string for DisplayAlert()*/
x=8*(80-strlen(why))/2;
whyindeed[1]=x;
whyindeed[0]=x>>8;
whyindeed[2]=14;
strcpy(&whyindeed[3],why);
whyindeed[strlen(&whyindeed[3])+4]=NULL;
DisplayAlert(RECOVERY_ALERT,whyindeed,24); /*Display the alert*/
if(err!=0)
exit(err);
}
PushIn(Item) /*Increase and redraw the level of an item*/
struct LineItem *Item;
{
struct LineItem *Start,*End,*work;
for(work=(struct LineItem *)Item;(work->PrevItem!=NULL) && (work->cont);
work=(struct LineItem *)work->PrevItem);
Start=(struct LineItem *)work;
for(work=(struct LineItem *)Item;(work->NextItem != NULL) &&
(work->NextItem->cont);work=(struct LineItem *)work->NextItem);
End=(struct LineItem *)work;
if(Start != End)
PushInBlock(Start,End,IsOnScreen(Start),FALSE);
else
if(Push(Item))
{
RedrawOutlineChars(Item,Item->Level-1,Item->Level);
return(TRUE);
}
else
return(FALSE);
}
Push(Item) /*Increase the level of an item (I. to A., etc.)*/
struct LineItem *Item;
{
if(Item->Level==6)
return(FALSE);
RemItem(Item);
Item->Level++; /*Increase the level and chop off excess text if it*/
Item->Text[MaxLen(Item->Level)]=NULL; /*would go off the line*/
AddItem(Item);
if(IsOnScreen(Item)) /*Print item if it is on screen*/
PrintItem(Item);
return(TRUE);
}
PullOut(Item) /*Decrease the level of an item and redraw*/
struct LineItem *Item;
{
struct LineItem *Start,*End,*work;
for(work=(struct LineItem *)Item;(work->PrevItem!=NULL) && (work->cont);
work=(struct LineItem *)work->PrevItem);
Start=(struct LineItem *)work;
for(work=(struct LineItem *)Item;(work->NextItem != NULL) &&
(work->NextItem->cont);work=(struct LineItem *)work->NextItem);
End=(struct LineItem *)work;
if(Start != End) /*If the line is a continuation or has continuing lines...*/
PullOutBlock(Start,End,IsOnScreen(Start),FALSE); /*Pull 'em all out*/
else
if(Pull(Item))
{
RedrawOutlineChars(Item,Item->Level+1,Item->Level);
return(TRUE);
}
else
return(FALSE);
}
Pull(Item) /*Decrease the level of an item (a. to 1., etc.)*/
struct LineItem *Item;
{
struct LineItem *wrk;
if(Item->Level==1)
return(FALSE);
for(wrk=(struct LineItem *)Item->NextItem;(wrk != NULL) && (wrk->cont);
wrk=(struct LineItem *)wrk->NextItem);
RemItem(Item);
Item->Level--;
AddItem(Item);
AddItem(wrk);
if(IsOnScreen(Item)) /*Print item if it is on screen*/
PrintItem(Item);
return(TRUE);
}
PushInBlock(TrueStart,TrueEnd,YStart,Inverse) /*Indent a reversed block*/
struct LineItem *TrueStart,*TrueEnd;
UBYTE YStart;
BYTE Inverse;
{
struct LineItem *Item,*Start,*End;
UBYTE OldX=CurX;
UBYTE OldY=CurY;
UBYTE Y=YStart;
/*If Start or End is a continued item, find where the continued items end*/
Start=(struct LineItem *)FindPrevNonCont(TrueStart);
End=(struct LineItem *)FindNextNonCont(TrueEnd);
Item=(struct LineItem *)Start; /*Check to see if any items are as*/
while(Item != End) /*pushed in as possible*/
{
if(Item->Level == 6)
return(FALSE);
Item=(struct LineItem *)Item->NextItem;
}
if(Y=IsOnScreen(Start))
PlotCursor(1,Y);
Item=(struct LineItem *)Start; /*Do first one*/
Push(Item);
while(Item != End) /*Loop until all pushed in*/
{
Item=(struct LineItem *)Item->NextItem;
if(Y=IsOnScreen(Item)) /*If it's on the screen*/
PlotCursor(1,Y);
Push(Item);
}
RemItem(Start);
AddItem(Start);
if(IsOnScreen(Item->NextItem))
{
PlotCursor(1,++Y); /*Redraw outline characters*/
RedrawOutlineChars(End->NextItem,6,5);
PlotCursor(1,Y);
RedrawOutlineChars(End->NextItem,4,3);
PlotCursor(1,Y);
RedrawOutlineChars(End->NextItem,2,1);
}
else
if(IsBefore(Item,FirstScrnItem))
{
Y=1;
PlotCursor(1,Y); /*Redraw outline characters*/
RedrawOutlineChars(FirstScrnItem,6,5);
PlotCursor(1,Y);
RedrawOutlineChars(FirstScrnItem,4,3);
PlotCursor(1,Y);
RedrawOutlineChars(FirstScrnItem,2,1);
}
PlotCursor(1,YStart);
if(Inverse)
RvsBlock(TrueStart,TrueEnd);
if(OldX < MinX(CurrentItem)) /*OldX might no longer be possible if*/
PlotCursor(MinX(CurrentItem),OldY); /*CurrentItem was one pushed in*/
else
PlotCursor(OldX,OldY);
}
PullOutBlock(TrueStart,TrueEnd,YStart,Inverse) /*Indent a reversed block*/
struct LineItem *TrueStart,*TrueEnd;
UBYTE YStart;
BYTE Inverse;
{
struct LineItem *Item,*Start,*End;
UBYTE OldX=CurX;
UBYTE OldY=CurY;
UBYTE Y;
Start=(struct LineItem *)FindPrevNonCont(TrueStart);
End=(struct LineItem *)FindNextNonCont(TrueEnd);
Item=(struct LineItem *)Start; /*Check to see if any items are as*/
while(Item != End) /*pushed in as possible*/
{
if(Item->Level == 1)
return(FALSE);
Item=(struct LineItem *)Item->NextItem;
}
if(Y=IsOnScreen(Start))
PlotCursor(1,Y);
Item=(struct LineItem *)Start; /*Do first one*/
Pull(Item);
while(Item != End) /*Loop until all pushed in*/
{
Item=(struct LineItem *)Item->NextItem;
if(Y=IsOnScreen(Item))
PlotCursor(1,Y);
Pull(Item);
}
Item=(struct LineItem *)Item->NextItem;
RemItem(Start);
AddItem(Start);
if(Y=IsOnScreen(Item))
{
PlotCursor(1,Y); /*Redraw outline characters*/
RedrawOutlineChars(Item,6,5);
PlotCursor(1,Y);
RedrawOutlineChars(Item,4,3);
PlotCursor(1,Y);
RedrawOutlineChars(Item,2,1);
}
else
if(IsBefore(Item,FirstScrnItem))
{
Y=1;
PlotCursor(1,Y); /*Redraw outline characters*/
RedrawOutlineChars(FirstScrnItem,6,5);
PlotCursor(1,Y);
RedrawOutlineChars(FirstScrnItem,4,3);
PlotCursor(1,Y);
RedrawOutlineChars(FirstScrnItem,2,1);
}
PlotCursor(1,YStart);
if(Inverse)
RvsBlock(TrueStart,TrueEnd);
if(OldX > MaxX(CurrentItem)) /*OldX might no longer be possible if*/
PlotCursor(MaxX(CurrentItem),OldY); /*CurrentItem was one pushed in*/
else
PlotCursor(OldX,OldY);
}
void PrintItemList(FrstItem,StartY) /*Prints a specified number of items*/
struct LineItem *FrstItem;
int StartY;
{
struct LineItem *CrntItem;
int y;
char Buffer[3];
CancelLineInvs(); /*Cancel any highlighted text on a line*/
if(InvsMode < NOINV ) /*If a block is highlighted somewhere...*/
if( InvsMode == BLOCK_DOWN)
{ /*and if the line is in the block*/
if( (IsAfter(FrstItem,StartIItem)) && (IsBefore(FrstItem,EndIItem)) )
WriteConsole(Inv,-1);
}
else /*make sure it's highlighted*/
if( (IsAfter(FrstItem,EndIItem)) && (IsBefore(FrstItem,StartIItem)) )
WriteConsole(Inv,-1);
PlotCursor(1,StartY); /*Start at the top...*/
CrntItem=(struct LineItem *)FrstItem;
Buffer[0]=0x9b;
Buffer[1]=0x4a;
WriteConsole(Buffer,2);
for(y=StartY;y<=SCRNHEIGHT && CrntItem!=NULL;y++)
{
if(InvsMode < 0) /*If inversed at and the start of a block...*/
if((CrntItem == StartIItem) &&
((InvsMode == BLOCK_DOWN) || (InvsMode == BLOCK_PENDING)) )
WriteConsole(Inv,-1); /*Make sure the line is highlighted*/
else
if((CrntItem == EndIItem) && (InvsMode == BLOCK_UP))
WriteConsole(Inv,-1); /*if it's in the block*/
PlotCursor(1,y);
PrintItem(CrntItem);
ScrnBtm=(struct LineItem *)CrntItem;
if(InvsMode < 0) /*If inversed and at the end of a block*/
if((CrntItem == EndIItem) &&
( (InvsMode == BLOCK_DOWN) || (InvsMode==BLOCK_PENDING) ))
WriteConsole(Norm,-1); /*Turn off highlighting*/
else
if((CrntItem == StartIItem) && (InvsMode == BLOCK_UP))
WriteConsole(Norm,-1);
CrntItem=(struct LineItem *)CrntItem->NextItem;
}
DispRows=y-1;
WriteConsole(Norm,-1);
}
void GetOutlineChars(Item,ConsoleBuffer) /*Get the outline chars (IX.,B.,etc.)*/
struct LineItem *Item; /*for an item*/
char *ConsoleBuffer;
{
int Level,StrLen,InsLen,c;
Level=RealLevel(Item)-1;
if(Item->cont)
InsLen=MinX(Item)-3;
else
{
StrLen=strlen(OutLineChars[Level][(Item->ItemNumber)]);
InsLen=PERPOS((Item->Level)-1)-StrLen;
}
for(c=0;c<InsLen;c++)
strcat(ConsoleBuffer," ");
if(!(Item->cont))
strcat(ConsoleBuffer,OutLineChars[Level][(Item->ItemNumber)]);
}
void RedrawOutlineChars(Item,Hi,Lo) /*Redraw the outline characters */
struct LineItem *Item; /*(Lo <= Changed level <= Hi)*/
int Hi,Lo;
{
char Buffer[60];
int x=1;
int y,Level;
Level=Item->Level;
for(y=CurY;y<=SCRNHEIGHT & Item != NULL ;y++)
{
if(Lo == Item->Level || Hi == Item->Level)
{
PlotCursor(x,y);
strcpy(Buffer,"");
GetOutlineChars(Item,Buffer);
WriteConsole(Buffer,-1);
}
Item=(struct LineItem *)Item->NextItem;
}
}
/*Insert an item into the item list*/
extern struct LineItem *InsertItem(NextItem,PrevItem)
struct LineItem *NextItem,*PrevItem;
{
struct LineItem *Item;
Forbid(); /*Make sure that nobody grabs memory inbetween the*/
/*AvailMem() and the AllocMem()*/
if(AvailMem(MEMF_LARGEST)<MINMEMORY) /*If we're out of memory*/
{
Permit();
return(NULL);
}
if((Item=(struct LineItem *)AllocMem(sizeof(struct LineItem),
MEMF_CLEAR))==NULL)
{
Permit();
return(NULL);
}
Permit();
if(NextItem != NULL)
{
NextItem->PrevItem=(struct LineItem *)Item;
Item->NextItem=(struct LineItem *)NextItem;
}
if(PrevItem != NULL)
{
PrevItem->NextItem=(struct LineItem *)Item;
Item->PrevItem=(struct LineItem *)PrevItem;
}
return(Item);
}
RemItem(Item) /*Adjust the ItemNumbers for items after one is removed*/
struct LineItem *Item;
{
int ItemNumber;
struct LineItem *WorkingItem;
if((Item->cont) || Item==NULL) /*If a continued line, or if there*/
return(FALSE); /*is no item, just return*/
if((WorkingItem=(struct LineItem *)FindPrev(Item))==NULL)
ItemNumber=0;
else
ItemNumber=Item->ItemNumber;
while((Item=(struct LineItem *)FindNext(Item))!=NULL)
{
if(ItemNumber==MaxNumOnLevel[Item->Level]-1)
ItemNumber=0;
Item->ItemNumber=ItemNumber++;
}
}
void AddItem(Item) /*Adjust the ItemNumbers after adding an item*/
struct LineItem *Item;
{
int ItemNumber;
struct LineItem *CrntItem;
if(Item->cont) /*If a continued line*/
return; /*just return*/
if((CrntItem=(struct LineItem *)FindPrev(Item))==NULL)
ItemNumber=0;
else
ItemNumber=CrntItem->ItemNumber+1;
do /*Go through the outline, updating ItemNumbers*/
{
if(ItemNumber==MaxNumOnLevel[Item->Level]-1)
ItemNumber=0;
Item->ItemNumber=ItemNumber++;
Item=(struct LineItem *)FindNext(Item);
}
while(Item != NULL && Item->PrevItem->Level >= Item->Level);
}
extern struct LineItem *FindPrev(Item) /*Find the previous item of*/
struct LineItem *Item; /*the same Level as Item*/
{
int Level;
Level=Item->Level;
Item=(struct LineItem *)Item->PrevItem;
while( ((Item->cont) || (Item->Level > Level)) && (Item !=NULL) )
Item=(struct LineItem *)Item->PrevItem;
if(Item->Level < Level || Item == NULL)
return(NULL);
else
return(Item);
}
extern struct LineItem *FindNext(Item) /*Find the next item of the same*/
struct LineItem *Item; /*Level as Item*/
{
int Level;
Level=Item->Level;
Item=(struct LineItem *)Item->NextItem;
while( ( (Item->cont) || (Item->Level > Level) ) && (Item != NULL) )
Item=(struct LineItem *)Item->NextItem;
if((Item->Level < Level) || (Item->cont) )
return(NULL);
else
return(Item);
}
void InsertLineAtTop() /*Insert a line at the top of the list*/
{
struct LineItem *WorkingItem;
WorkingItem=(struct LineItem *)
InsertItem(FirstItem,NULL);
if(WorkingItem==NULL) /*Out of memory*/
{
Leave(0,"Memory too fragmented to add line!");
return;
}
WorkingItem->Level=1;
FirstItem=(struct LineItem *)WorkingItem;
AddItem(FirstItem);
PlotCursor(1,1);
RedrawOutlineChars(WorkingItem->NextItem,1,1);
PlotCursor(MinX(CurrentItem),1);
CursorUp();
}
IsOnScreen(item) /*Test to see whether a LineItem is currently*/
struct LineItem *item; /*on the screen, and if so, return its Y position*/
{
struct LineItem *wrk;
int y;
/*Search items on screen for a match*/
for(y=1,wrk=(struct LineItem *)FirstScrnItem;(wrk!=item) && (wrk!=ScrnBtm);
wrk=(struct LineItem *)wrk->NextItem,y++);
if(wrk == item)
return(y); /*It's on screen*/
else
return(FALSE);
}
IsBefore(item,start) /*Checks to see if 'item' if before 'start' in*/
struct LineItem *start,*item; /*the linked list*/
{
for(;(start != item) && (start != NULL);
start=(struct LineItem *)start->PrevItem);
if(start==item)
return(TRUE);
else
return(FALSE);
}
IsAfter(item,start) /*Checks to see if 'item' is after 'start' in the*/
struct LineItem *start,*item; /*linked list*/
{
for(;(start != item) && (start != NULL);
start=(struct LineItem *)start->NextItem);
if(start==item)
return(TRUE);
else
return(FALSE);
}
extern struct LineItem *FindPrevNonCont(Start)/*Find the first line before*/
struct LineItem *Start; /*or at 'Start' that isn't a continuation*/
{
struct LineItem *Item;
for(Item=(struct LineItem *)Start;(Item->PrevItem!=NULL)&&(Item->cont);
Item=(struct LineItem *)Item->PrevItem);
return(Item);
}
extern struct LineItem *FindNextNonCont(Start) /*Find the first non-*/
struct LineItem *Start; /*continuation after 'Start'*/
{
struct LineItem *Item;
for(Item=(struct LineItem *)Start;(Item->NextItem != NULL) &&
(Item->NextItem->cont);Item=(struct LineItem *)Item->NextItem);
return(Item);
}
CursorUp() /*Move the cursor up (scroll screen, etc.)*/
{
char Buffer[20];
int TempX;
CancelLineInvs();
if(ErrorInTitle)
TitleErrorCancel();
if(CurrentItem->PrevItem !=NULL)
{
if(CurrentItem==FirstScrnItem && CurrentItem != FirstItem)
{
TempX=CurX; /*Delete the last line*/
PlotCursor(1,SCRNHEIGHT);
Buffer[0]=0x9b;
Buffer[1]=0x4a;
WriteConsole(Buffer,2);
PlotCursor(TempX,1);
strcpy(Buffer,&SpecChars[SCPos[0x0c]]);
WriteConsole(Buffer,2);
if(prefs.DS)
WriteConsole(Buffer,2); /*If double spaced, scroll twice*/
TempX=CurX;
PlotCursor(1,1);
if(InvsMode < NOINV) /*Block Invs is active somewhere*/
switch(InvsMode)
{
case BLOCK_PENDING:
if(CurrentItem->PrevItem == StartIItem)
WriteConsole(Inv,-1); /*Inverse*/
break;
case BLOCK_DOWN:
if(IsAfter(CurrentItem->PrevItem,StartIItem) && /*If it's in*/
IsBefore(CurrentItem->PrevItem,EndIItem)) /*the block*/
WriteConsole(Inv,-1); /*Inverse*/
break;
case BLOCK_UP:
if(IsAfter(CurrentItem->PrevItem,EndIItem) && /*Same as*/
IsBefore(CurrentItem->PrevItem,StartIItem)) /*above*/
WriteConsole(Inv,-1);
}
PrintItem(CurrentItem->PrevItem);
WriteConsole(Norm,-1); /*Make it normal again*/
++CurY;
if(ScrnBtm==LastItem && DispRows < SCRNHEIGHT)
++DispRows;
else
ScrnBtm=(struct LineItem *)ScrnBtm->PrevItem;
FirstScrnItem=(struct LineItem *)FirstScrnItem->PrevItem;
CurX=TempX;
InvY++;
}
if(CurX < MinX(CurrentItem->PrevItem)) /*If the cursor wouldn't be*/
CurX=MinX(CurrentItem->PrevItem); /*in a legal place on the line*/
else /*now, move it onto the line*/
if(CurX > MaxX(CurrentItem->PrevItem))
CurX=MaxX(CurrentItem->PrevItem);
PlotCursor(CurX,CurY-1); /*Position the cursor*/
CurrentItem=(struct LineItem *) CurrentItem->PrevItem;
return(TRUE);
}
return(FALSE);
}
CursorDown() /*Move the cursor down (scroll screen, etc.)*/
{
char Buffer[20];
int TempX;
CancelLineInvs();
if(ErrorInTitle)
TitleErrorCancel();
if(CurrentItem->NextItem != NULL)
{
if(CurrentItem==ScrnBtm)
{
strcpy(Buffer,&SpecChars[SCPos[0x0d]]);
WriteConsole(Buffer,2);
if(prefs.DS) /*If double spaced, scroll twice*/
{
WriteConsole(Buffer,2);
WriteConsole(Buffer,2);
if(Odd)
WriteConsole(Buffer,2);
}
TempX=CurX;
PlotCursor(1,CurY);
if(InvsMode < NOINV) /*Block Invs is active somewhere*/
switch(InvsMode)
{
case BLOCK_PENDING:
if(CurrentItem->NextItem == StartIItem)
WriteConsole(Inv,-1); /*Inverse*/
break;
case BLOCK_DOWN:
if(IsAfter(CurrentItem->NextItem,StartIItem) && /*If it's in*/
IsBefore(CurrentItem->NextItem,EndIItem)) /*the block*/
WriteConsole(Inv,-1); /*Inverse*/
break;
case BLOCK_UP:
if(IsAfter(CurrentItem->NextItem,EndIItem) && /*Same as*/
IsBefore(CurrentItem->NextItem,StartIItem)) /*above*/
WriteConsole(Inv,-1);
}
PrintItem(CurrentItem->NextItem);
WriteConsole(Norm,-1);
PlotCursor(TempX,CurY-1);
ScrnBtm=(struct LineItem *)CurrentItem->NextItem;
FirstScrnItem=(struct LineItem *)FirstScrnItem->NextItem;
InvY--;
}
if(CurX < MinX(CurrentItem->NextItem)) /*If the cursor wouldn't be on*/
CurX=MinX(CurrentItem->NextItem); /*the new line, move it*/
else
if(CurX > MaxX(CurrentItem->NextItem))
CurX=MaxX(CurrentItem->NextItem);
PlotCursor(CurX,CurY+1);
CurrentItem=(struct LineItem *)CurrentItem->NextItem; /*Update the */
return(TRUE); /*Current line pointer*/
}
return(FALSE);
}
/*End of liner.c*/